#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
缓存管理器
用于保存和加载统计结果缓存
"""

import os
import json
import hashlib
import datetime
from typing import Dict, Optional, Tuple


class CacheManager:
    """统计结果缓存管理器"""
    
    CACHE_VERSION = "1.0"
    
    def __init__(self, cache_dir: str = None):
        """
        初始化缓存管理器
        
        Args:
            cache_dir: 缓存目录路径，默认为用户主目录下的 .git-counter-cache
        """
        if cache_dir is None:
            # 使用用户主目录下的缓存目录，无论程序在哪里运行都能访问
            cache_dir = os.path.join(os.path.expanduser("~"), ".git-counter-cache")
        
        self.cache_dir = cache_dir
        # 确保缓存目录存在
        os.makedirs(cache_dir, exist_ok=True)
    
    def generate_cache_filename(self, repo_path: str, users: list, branch: str, stat_mode: str) -> str:
        """
        生成缓存文件名
        
        Args:
            repo_path: 仓库路径
            users: 用户列表
            branch: 分支名
            stat_mode: 统计模式 (summary/detailed)
        
        Returns:
            缓存文件名
        """
        # 统一路径格式（统一使用反斜杠，并转换为绝对路径）
        normalized_path = os.path.abspath(repo_path).replace('/', '\\')
        
        # 仓库路径哈希（取前8位）
        repo_hash = hashlib.md5(normalized_path.encode('utf-8')).hexdigest()[:8]
        
        # 用户列表哈希（排序后保证一致性）
        users_str = ','.join(sorted(users))
        users_hash = hashlib.md5(users_str.encode('utf-8')).hexdigest()[:8]
        
        # 组合文件名
        filename = f"cache_{repo_hash}_{users_hash}_{branch}_{stat_mode}.json"
        
        return filename
    
    def save_cache(self, repo_path: str, users: list, branch: str, stat_mode: str, 
                   last_commit_id: str, last_commit_time: str, total_commits: int,
                   stats: Dict, file_stats: Dict, per_user_stats: Dict = None, 
                   user_list: list = None) -> str:
        """
        保存统计结果到缓存
        
        Args:
            repo_path: 仓库路径
            users: 用户列表
            branch: 分支名
            stat_mode: 统计模式
            last_commit_id: 最后一次提交的ID
            last_commit_time: 最后一次提交的时间
            total_commits: 总提交数
            stats: 统计数据
            file_stats: 文件统计数据
            per_user_stats: 分账户统计数据（可选）
            user_list: 用户显示列表（可选）
        
        Returns:
            缓存文件路径
        """
        # 统一路径格式
        normalized_repo_path = os.path.abspath(repo_path).replace('/', '\\')
        
        filename = self.generate_cache_filename(repo_path, users, branch, stat_mode)
        filepath = os.path.join(self.cache_dir, filename)
        
        # 构建缓存数据
        cache_data = {
            "metadata": {
                "cache_version": self.CACHE_VERSION,
                "repo_path": normalized_repo_path,
                "branch": branch,
                "users": users,
                "stat_mode": stat_mode,
                "last_commit_id": last_commit_id,
                "last_commit_time": last_commit_time,
                "cache_create_time": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                "total_commits": total_commits
            },
            "stats": stats,
            "file_stats": dict(file_stats),  # 转换defaultdict为普通dict
            "per_user_stats": per_user_stats if per_user_stats else {},
            "user_list": user_list if user_list else []
        }
        
        # 保存到文件
        try:
            with open(filepath, 'w', encoding='utf-8') as f:
                json.dump(cache_data, f, indent=2, ensure_ascii=False)
            return filepath
        except Exception as e:
            raise Exception(f"保存缓存失败: {e}")
    
    def load_cache(self, repo_path: str, users: list, branch: str, stat_mode: str) -> Optional[Dict]:
        """
        加载缓存
        
        Args:
            repo_path: 仓库路径
            users: 用户列表
            branch: 分支名
            stat_mode: 统计模式
        
        Returns:
            缓存数据，如果不存在返回None
        """
        filename = self.generate_cache_filename(repo_path, users, branch, stat_mode)
        filepath = os.path.join(self.cache_dir, filename)
        
        print(f"[load_cache 调试]")
        print(f"  查找文件名: {filename}")
        print(f"  完整路径: {filepath}")
        print(f"  文件是否存在: {os.path.exists(filepath)}")
        
        if not os.path.exists(filepath):
            # 列出缓存目录中的所有文件
            if os.path.exists(self.cache_dir):
                print(f"  缓存目录中的文件:")
                for f in os.listdir(self.cache_dir):
                    print(f"    - {f}")
            return None
        
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                cache_data = json.load(f)
            return cache_data
        except Exception as e:
            print(f"加载缓存失败: {e}")
            return None
    
    def validate_cache(self, cache_data: Dict, current_repo, current_users: list, 
                      current_branch: str, current_mode: str) -> Tuple[bool, str]:
        """
        验证缓存是否有效
        
        Args:
            cache_data: 缓存数据
            current_repo: 当前Git仓库对象
            current_users: 当前用户列表
            current_branch: 当前分支
            current_mode: 当前统计模式
        
        Returns:
            (是否有效, 原因说明)
        """
        if not cache_data:
            return False, "缓存数据为空"
        
        metadata = cache_data.get('metadata', {})
        
        # 1. 检查缓存版本
        if metadata.get('cache_version') != self.CACHE_VERSION:
            return False, "缓存版本不兼容"
        
        # 2. 检查仓库路径是否匹配（统一路径格式）
        cached_path = os.path.abspath(metadata.get('repo_path', '')).replace('/', '\\')
        current_path = os.path.abspath(current_repo.working_dir).replace('/', '\\')
        if cached_path != current_path:
            return False, "仓库路径不匹配"
        
        # 3. 检查分支是否匹配
        if metadata.get('branch') != current_branch:
            return False, f"分支已切换 ({metadata.get('branch')} → {current_branch})"
        
        # 4. 检查用户列表是否匹配
        cached_users = set(metadata.get('users', []))
        current_users_set = set(current_users)
        if cached_users != current_users_set:
            return False, "统计用户已改变"
        
        # 5. 检查统计模式
        if metadata.get('stat_mode') != current_mode:
            return False, f"统计模式已改变 ({metadata.get('stat_mode')} → {current_mode})"
        
        # 6. 检查最后提交ID
        try:
            current_commit_id = current_repo.head.commit.hexsha
            cached_commit_id = metadata.get('last_commit_id')
            
            if current_commit_id != cached_commit_id:
                # 计算新增提交数
                try:
                    commits_between = list(current_repo.iter_commits(
                        f"{cached_commit_id}..{current_commit_id}"
                    ))
                    new_commits_count = len(commits_between)
                    return False, f"有 {new_commits_count} 个新提交"
                except:
                    return False, "有新的提交"
        except Exception as e:
            return False, f"无法检查提交状态: {e}"
        
        # 所有检查通过
        return True, "缓存有效"
    
    def get_cache_info(self, cache_data: Dict) -> Dict:
        """
        获取缓存信息摘要
        
        Args:
            cache_data: 缓存数据
        
        Returns:
            缓存信息字典
        """
        if not cache_data:
            return {}
        
        metadata = cache_data.get('metadata', {})
        
        return {
            'create_time': metadata.get('cache_create_time', '未知'),
            'last_commit_time': metadata.get('last_commit_time', '未知'),
            'last_commit_id': metadata.get('last_commit_id', 'unknown')[:8],  # 只显示前8位
            'total_commits': metadata.get('total_commits', 0),
            'users': metadata.get('users', []),
            'branch': metadata.get('branch', 'unknown'),
            'stat_mode': metadata.get('stat_mode', 'unknown')
        }
    
    def clear_old_caches(self, days: int = 30) -> int:
        """
        清理超过指定天数的旧缓存
        
        Args:
            days: 保留天数
        
        Returns:
            清理的缓存文件数量
        """
        if not os.path.exists(self.cache_dir):
            return 0
        
        count = 0
        now = datetime.datetime.now()
        cutoff = now - datetime.timedelta(days=days)
        
        for filename in os.listdir(self.cache_dir):
            if not filename.startswith('cache_') or not filename.endswith('.json'):
                continue
            
            filepath = os.path.join(self.cache_dir, filename)
            
            try:
                # 检查文件修改时间
                mtime = datetime.datetime.fromtimestamp(os.path.getmtime(filepath))
                if mtime < cutoff:
                    os.remove(filepath)
                    count += 1
            except Exception:
                continue
        
        return count
    
    def clear_all_caches(self) -> int:
        """
        清理所有缓存
        
        Returns:
            清理的缓存文件数量
        """
        if not os.path.exists(self.cache_dir):
            return 0
        
        count = 0
        for filename in os.listdir(self.cache_dir):
            if not filename.startswith('cache_') or not filename.endswith('.json'):
                continue
            
            filepath = os.path.join(self.cache_dir, filename)
            
            try:
                os.remove(filepath)
                count += 1
            except Exception:
                continue
        
        return count
    
    def get_cache_size(self) -> str:
        """
        获取缓存目录总大小
        
        Returns:
            格式化的大小字符串
        """
        if not os.path.exists(self.cache_dir):
            return "0 B"
        
        total_size = 0
        for filename in os.listdir(self.cache_dir):
            filepath = os.path.join(self.cache_dir, filename)
            if os.path.isfile(filepath):
                total_size += os.path.getsize(filepath)
        
        # 格式化大小
        for unit in ['B', 'KB', 'MB', 'GB']:
            if total_size < 1024.0:
                return f"{total_size:.1f} {unit}"
            total_size /= 1024.0
        
        return f"{total_size:.1f} TB"
    
    def get_cache_count(self) -> int:
        """
        获取缓存文件数量
        
        Returns:
            缓存文件数量
        """
        if not os.path.exists(self.cache_dir):
            return 0
        
        count = 0
        for filename in os.listdir(self.cache_dir):
            if filename.startswith('cache_') and filename.endswith('.json'):
                count += 1
        
        return count

